#include "Hostage.h"

// DEFAULT CONSTRUCTOR
Hostage::Hostage( char * fileName, int id, Pathfinder & pather, Grid<char> & occGrid,
				 float walkSpeed, float turnSpeed)
				 : Agent( fileName, id, pather, occGrid, walkSpeed, turnSpeed ), isFlipped( false )
{
	speed = 0;
	currPath = list<Triple>();
	traverser = PathTraverser( & currPath, walkSpeed, turnSpeed );
}

Hostage::~Hostage(void)
{
}

// get Hostage ID
int Hostage::getID()
{
	return this->hostageID;
}


// get state.
int Hostage::getState()
{
	return this->currentState;
}

// set state.
void Hostage::setState(int state)
{
	this->currentState = state;
}

// check if hostile is nearby
bool Hostage::hostileNear()
{
	bool isFree = false;				// default value set to false.
	int distance = 50;					// distance our dude can "see"

	Position squaresInLOS[8];			// array to store 3D values in line-of-sight
	Triple gridSquaresInLOS[8];			// DEBUG: array to store grid values in line-of-sight

	// get current robot position
	Triple p = getPosition();

	// calculate various offsets for N/W/E/NW/NE
	float direction = dbWrapValue(getRotY());
	float newX = dbNewXValue( p.x, direction, distance );
	float newZ = dbNewZValue( p.z, direction, distance );
	Triple N = Triple( newX, p.y, newZ );					// N

	direction = dbWrapValue(getRotY() - 90 );
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple W = Triple( newX, p.y, newZ );					// W

	direction = dbWrapValue(getRotY() + 90);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple E = Triple( newX, p.y, newZ );					// E

	direction = dbWrapValue(getRotY() - 45);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple NW = Triple( newX, p.y, newZ );					// NW

	direction = dbWrapValue(getRotY() + 45);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple NE = Triple( newX, p.y, newZ );					// NE

	// new calculations for 360 FOV
	direction = dbWrapValue(getRotY() + 180);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple S = Triple( newX, p.y, newZ );					// S

	direction = dbWrapValue(getRotY() - 135);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple SW = Triple( newX, p.y, newZ );					// SW

	direction = dbWrapValue(getRotY() + 135);
	newX = dbNewXValue( p.x, direction, distance );
	newZ = dbNewZValue( p.z, direction, distance );
	Triple SE = Triple( newX, p.y, newZ );					// SE


	// build 3D line-of-sight vector with offset of distance
	squaresInLOS[0] = pathfinder.posToGrid(N);				// check N
	squaresInLOS[1] = pathfinder.posToGrid(W);				// check W
	squaresInLOS[2] = pathfinder.posToGrid(E);				// check E
	squaresInLOS[3] = pathfinder.posToGrid(NW);				// check NW
	squaresInLOS[4] = pathfinder.posToGrid(NE);				// check NE
	squaresInLOS[5] = pathfinder.posToGrid(S);				// check S
	squaresInLOS[6] = pathfinder.posToGrid(SW);				// check SW
	squaresInLOS[7] = pathfinder.posToGrid(SE);				// check SE

	// DEBUG: build GRID line-of-sight vector with offset of distance
	gridSquaresInLOS[0] = N;
	gridSquaresInLOS[1] = W;
	gridSquaresInLOS[2] = E;
	gridSquaresInLOS[3] = NW;
	gridSquaresInLOS[4] = NE;
	gridSquaresInLOS[5] = S;
	gridSquaresInLOS[6] = SW;
	gridSquaresInLOS[7] = SE;

	// DEBUG: color grids we are checking
	for (int i=0; i<8; i++)
	{
		int tmpID = 5700+i;
		dbMakeObjectPlane		( tmpID , 30, 30 );
		dbXRotateObject			( tmpID , -90 );
		dbPositionObject		( tmpID , gridSquaresInLOS[i].x, 0.5, gridSquaresInLOS[i].z);
		dbColorObject			( tmpID, dbRGB(255,0,0) );
		dbSetObjectCollisionOff ( tmpID );
		dbGhostObjectOn( tmpID );
	}

	// check line-of-sight vector.
	for (int i=0; i<8; i++)
	{
		// TODO: check for occlusion
		int foo = occGrid(squaresInLOS[i].x, squaresInLOS[i].z);

		if (foo != 9)		// hostile is NOT nearby
		{
			setState(FREE);
			isFree = true;
		}
	}

	return isFree;
}

// update hostile 
void Hostage::update()
{
	if (hostileNear() == false)
	{
		// we are free to flee!
		// TODO JYY : initiate run away action.
		// moveTo(exitPath);
	}
}